﻿/**************************************************************
 *
 * 命名空间：Sgr.DataCategories.Domain
 * 创建时间：2025/3/19
 * 描述：行政区划领域服务实现
 *
 **************************************************************/

using Sgr.Domain.Entities;
using Sgr.Domain.Managers;
using Sgr.Exceptions;
using Sgr.Generator;
using Sgr.Domain.Repositories;
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace Sgr.DataCategories.Domain.AdministrativeDivisions
{
    /// <summary>
    /// 行政区划领域服务实现
    /// </summary>
    public class AdministrativeDivisionManage : TreeNodeManageBase<AdministrativeDivision, long>, IAdministrativeDivisionManage
    {
        private readonly ISegmentNumIdGenerator _numberIdGenerator;

        // 添加一个属性来安全地转换基类的仓储引用
        private IAdministrativeDivisionRepository AdministrativeDivisionRepository =>
            (IAdministrativeDivisionRepository)_repository;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="repository">行政区划仓储</param>
        /// <param name="numberIdGenerator">ID生成器</param>
        public AdministrativeDivisionManage(
            IAdministrativeDivisionRepository repository,
            ISegmentNumIdGenerator numberIdGenerator) : base(repository)
        {
            _numberIdGenerator = numberIdGenerator ?? throw new ArgumentNullException(nameof(numberIdGenerator));
        }

        /// <summary>
        /// 创建新的行政区划
        /// </summary>
        /// <param name="name">名称</param>
        /// <param name="code">代码</param>
        /// <param name="orderNumber">排序号</param>
        /// <param name="entityStates">状态</param>
        /// <param name="shortName">简称</param>
        /// <param name="pinyinName">拼音名称</param>
        /// <param name="pinyinAbbr">拼音缩写</param>
        /// <param name="description">描述</param>
        /// <param name="parentId">上级行政区划ID</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>行政区划领域对象</returns>
        public async Task<AdministrativeDivision> CreateNewAsync(
            string name,
            string code,
            int orderNumber,
            EntityStates entityStates,
            string? shortName = null,
            string? pinyinName = null,
            string? pinyinAbbr = null,
            string? description = null,
            long? parentId = null,
            CancellationToken cancellationToken = default)
        {
            if (entityStates == EntityStates.None)
                throw DomainException.ValidationError("行政区划状态未设置");

            // 检查代码唯一性
            DomainRuleCheckResult ruleCheckResult = await ValidateCodeIsUniqueAsync(code, null, cancellationToken);
            ruleCheckResult.HandleRule();

            // 获取ID及节点路径
            long id = await _numberIdGenerator.GetUniqueIdAsync("", cancellationToken);

            // 处理父节点ID及节点路径
            parentId ??= 0;

            // 如果有父节点，验证父节点存在且级别合适
            AdministrativeDivision? parentNode = null;
            if (parentId > 0)
            {
                parentNode = await AdministrativeDivisionRepository.GetAsync(parentId.Value, cancellationToken);
                if (parentNode == null)
                    throw DomainException.ValidationError($"上级行政区划ID {parentId} 不存在");

                if (parentNode.State == EntityStates.Deactivate)
                    throw DomainException.ValidationError($"上级行政区划 {parentNode.Name} 已停用，请先激活上级行政区划。");
            }

            // 生成节点路径
            string nodePath = GetNodePath(parentNode, id, 5);

            // 创建行政区划
            var entity = new AdministrativeDivision(
                name,
                code,
                shortName,
                pinyinName,
                pinyinAbbr,
                description)
            {
                Id = id,
                OrderNumber = orderNumber
            };
            entity.ChangeEntityState(entityStates);
            entity.SetParent(parentId.Value, nodePath);
            return entity;
        }

        /// <summary>
        /// 检查行政区划代码是否唯一
        /// </summary>
        /// <param name="code">代码</param>
        /// <param name="excludeId">排除的ID</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>是否唯一</returns>
        public async Task<DomainRuleCheckResult> ValidateCodeIsUniqueAsync(
            string code,
            long? excludeId = null,
            CancellationToken cancellationToken = default)
        {
            // 参数验证
            Check.StringNotNullOrEmpty(code, nameof(code));

            // 检查代码唯一性
            if (!await AdministrativeDivisionRepository.CodeIsUniqueAsync(code, excludeId, cancellationToken))
            {
                return DomainRuleCheckResult.Fail($"行政区划代码 {code} 已存在");
            }

            return DomainRuleCheckResult.Ok();
        }

        /// <summary>
        /// 激活行政区划及其子行政区划
        /// </summary>
        /// <param name="administrativeDivision">行政区划</param>
        /// <param name="cancellationToken">取消令牌</param>
        public async Task ActivateAsync(AdministrativeDivision administrativeDivision, CancellationToken cancellationToken = default)
        {
            Check.NotNull(administrativeDivision, nameof(administrativeDivision));

            if (administrativeDivision.State == EntityStates.Normal)
                return;

            //查找当前部门的上级部门，如果上级部门存在且处于停用状态，则抛出异常
            if (administrativeDivision.ParentId != 0)
            {
                var parentAdministrativeDivision = await AdministrativeDivisionRepository.GetAsync(administrativeDivision.ParentId, cancellationToken);
                if (parentAdministrativeDivision != null && parentAdministrativeDivision.State == EntityStates.Deactivate)
                    throw DomainException.LimitExceededError($"上级部门 {parentAdministrativeDivision.Name} 已停用，请先激活上级部门。");
            }

            await SetAdministrativeDivisionStateAsync(administrativeDivision, EntityStates.Normal, cancellationToken);
        }

        /// <summary>
        /// 停用行政区划及其子行政区划
        /// </summary>
        /// <param name="administrativeDivision">行政区划</param>
        /// <param name="cancellationToken">取消令牌</param>
        public async Task DeactivateAsync(AdministrativeDivision administrativeDivision, CancellationToken cancellationToken = default)
        {
            Check.NotNull(administrativeDivision, nameof(administrativeDivision));

            if (administrativeDivision.State == EntityStates.Deactivate)
                return;

            await SetAdministrativeDivisionStateAsync(administrativeDivision, EntityStates.Deactivate, cancellationToken);
        }

        /// <summary>
        /// 设置行政区划状态为指定的实体状态，并更新该行政区划及其所有子行政区划的状态
        /// </summary>
        /// <param name="administrativeDivision"></param>
        /// <param name="entityStates"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        private async Task SetAdministrativeDivisionStateAsync(AdministrativeDivision administrativeDivision, EntityStates entityStates, CancellationToken cancellationToken)
        {
            administrativeDivision.ChangeEntityState(entityStates);
            await AdministrativeDivisionRepository.UpdateAsync(administrativeDivision, cancellationToken);

            var children = await AdministrativeDivisionRepository.GetChildNodesRecursionAsync(administrativeDivision.NodePath, cancellationToken);
            foreach (var child in children)
            {
                child.ChangeEntityState(entityStates);
                await AdministrativeDivisionRepository.UpdateAsync(child, cancellationToken);
            }
        }

        /// <summary>
        /// 删除某个节点前的操作
        /// </summary>
        /// <param name="entity"></param>
        protected override void BeforeDeleteEntity(AdministrativeDivision entity)
        {
            base.BeforeDeleteEntity(entity);

            entity.MarkForDeletion();
        }

        /// <summary>
        /// 修改树节点的父节点
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="parentEntity"></param>
        /// <param name="maxLevel"></param>
        protected override void ChangeEntityParent(AdministrativeDivision entity, AdministrativeDivision? parentEntity, int maxLevel = 5)
        {
            long parentId = 0;

            if (parentEntity != null)
            {
                parentId = parentEntity!.Id;
            }

            string path = GetNodePath(parentEntity, entity.Id, maxLevel);

            entity.SetParent(parentId, path);
        }
    }
}